package com.cloud.job.service.impl;

import com.baomidou.dynamic.datasource.annotation.DS;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.cloud.api.domain.algorithm.Aggregation;
import com.cloud.api.domain.algorithm.VehiclePoint;
import com.cloud.api.domain.job.Addr;
import com.cloud.api.domain.job.VehicleMessageDaily;
import com.cloud.api.domain.job.VehicleRunningData;
import com.cloud.api.domain.report.VehicleOffline;
import com.cloud.api.myenum.VinYear;
import com.cloud.api.utils.ExcelUtils;
import com.cloud.job.config.DbscanConfig;
import com.cloud.job.config.MysqlConfig;
import com.cloud.job.config.ResolveAddress;
import com.cloud.job.mapper.VehicleMessageDailyMapper;
import com.cloud.job.service.EmailService;
import com.cloud.job.service.IVehicleMessageDailyService;
import com.google.common.util.concurrent.RateLimiter;
import jakarta.annotation.Resource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.MessageSource;
import org.springframework.context.i18n.LocaleContextHolder;
import org.springframework.stereotype.Service;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.List;
import java.util.Locale;


/**
 * @author 杨斌
 * 2024-03-1/3/2024
 */
@Service("vehicleMessageDailyService")
@DS("doris")
public class VehicleMessageDailyServiceImpl extends ServiceImpl<VehicleMessageDailyMapper, VehicleMessageDaily> implements IVehicleMessageDailyService {
    @Resource
    VehicleMessageDailyMapper vehicleMessageDailyMapper;

    @Resource
    private MessageSource messageSource;

    @Resource
    private EmailService emailService;

    @Autowired
    private MysqlConfig mysqlConfig;

    @Resource
    private ResolveAddress resolveAddress;

    @Resource
    private DbscanConfig dbscanConfig;

    private final RateLimiter rateLimiter = RateLimiter.create(1000.0);

    @Override
    public List<VehicleMessageDaily> getVehicleMessage() {
        return vehicleMessageDailyMapper.getVehicleMessage();
    }

    @Override
    public List<VehicleRunningData> getVehicleRunningData() {
        return vehicleMessageDailyMapper.getVehicleRunningData();
    }

    @Override
    public void exportMailOfflineList() {
        Locale locale = LocaleContextHolder.getLocale();
        String fileName = "table.vehicle.offline";
        List<VehicleOffline> vehicleOfflineList = vehicleMessageDailyMapper.selectOfflineList(mysqlConfig.getDataSource());
        vehicleOfflineList.forEach(vehicleOffline -> {
            String productionDate = vehicleOffline.getProductionDate();
            if (productionDate != null && productionDate.length() == 1) {
                char vinYearChar = productionDate.charAt(0);
                String yearOrChar = VinYear.fromChar(vinYearChar);
                vehicleOffline.setProductionDate(yearOrChar);
            }
        });
        fileName = messageSource.getMessage(fileName, null, fileName, locale);

        try (ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) {
            // 导出Excel文件到ByteArrayOutputStream
            ExcelUtils.export(outputStream, fileName, vehicleOfflineList, VehicleOffline.class);
            // 获取字节数组副本，用于后续邮件发送
            byte[] fileBytes = outputStream.toByteArray();
            // 异步发送邮件
            emailService.sendEmailAsync("离线车辆数据导出", "请查看附件中的离线车辆数据。", fileName + ".xlsx", fileBytes);
        } catch (IOException e) {
            log.error("导出Excel文件失败", e);
        }
    }

    @Override
    public void exportMailAggVehicleMessage() {
        Locale locale = LocaleContextHolder.getLocale();
        String fileName = "table.vehicle.aggregation";
        List <VehiclePoint> points = vehicleMessageDailyMapper.getAggVehicleMessage(dbscanConfig.getParkTime(), mysqlConfig.getDataSource());
        Aggregation aggregation = new Aggregation();
        List<VehiclePoint> pointList = aggregation.directDistance(points);
        for (VehiclePoint point : pointList) {
            String lat = String.valueOf(point.getLat());
            String lng = String.valueOf(point.getLng());
            Addr addr = resolveAddress.getAddr(lat, lng);
            point.setAddress(addr.getAddress());
            point.setProvinceCity(addr.getProvince() + addr.getCity());
        }
        fileName = messageSource.getMessage(fileName, null, fileName, locale);

        try (ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) {
            // 导出Excel文件到ByteArrayOutputStream
            ExcelUtils.export(outputStream, fileName, pointList, VehiclePoint.class);
            // 获取字节数组副本，用于后续邮件发送
            byte[] fileBytes = outputStream.toByteArray();
            // 异步发送邮件
            emailService.sendEmailAsync("车辆各省市运行情况导出", "请查看附件中的车辆各省市运行情况。", fileName + ".xlsx", fileBytes);
        } catch (IOException e) {
            log.error("导出Excel文件失败", e);
        }
    }

    @Override
    public List<VehicleOffline> getVehicleOfflineData() {
        List<VehicleOffline> vehicleOfflineList = vehicleMessageDailyMapper.selectOfflineList(mysqlConfig.getDataSource());
        vehicleOfflineList.forEach(vehicleOffline -> {
            String productionDate = vehicleOffline.getProductionDate();
            if (productionDate != null && productionDate.length() == 1) {
                char vinYearChar = productionDate.charAt(0);
                String yearOrChar = VinYear.fromChar(vinYearChar);
                vehicleOffline.setProductionDate(yearOrChar);
            }
        });
        return vehicleOfflineList;
    }

    @Override
    public List<VehiclePoint> getAggVehicleMessage() {
        List <VehiclePoint> points = vehicleMessageDailyMapper.getAggVehicleMessage(dbscanConfig.getParkTime(), mysqlConfig.getDataSource());
        Aggregation aggregation = new Aggregation();
        List<VehiclePoint> pointList = aggregation.directDistance(points);
        for (VehiclePoint point : pointList) {
            String productionDate = point.getProductionDate();
            if (productionDate != null && productionDate.length() == 1) {
                char vinYearChar = productionDate.charAt(0);
                String yearOrChar = VinYear.fromChar(vinYearChar);
                point.setProductionDate(yearOrChar);
            }
            String lat = String.valueOf(point.getLat());
            String lng = String.valueOf(point.getLng());
            rateLimiter.acquire();
            Addr addr = resolveAddress.getAddr(lat, lng);
            if(addr != null){
                point.setAddress(addr.getAddress());
                point.setProvinceCity(addr.getProvince() + addr.getCity());
            }
        }
        return pointList;
    }


}
